using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using System.IO;
using Qreed.Windows.Forms;
using Qreed.Diagnostics;

namespace GotLyrics
{
    /// <summary>
    /// 
    /// </summary>
    public partial class AudioFileSelectionControl : UserControl
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="AudioFileList"/> class.
        /// </summary>
        public AudioFileSelectionControl()
        {
            InitializeComponent();
        }

        
        #region Properties

        private List<AudioFileContext> _audioFiles = new List<AudioFileContext>();
        /// <summary>
        /// Gets the audio files.
        /// </summary>
        /// <value>The audio files.</value>
        public AudioFileContext[] AudioFiles
        {
            get { return _audioFiles.ToArray(); }
        }

        private List<AudioFileContext> _selectedAudioFiles = new List<AudioFileContext>();
        /// <summary>
        /// Gets the selected audio files.
        /// </summary>
        /// <value>The selected audio files.</value>
        public AudioFileContext[] SelectedAudioFiles
        {
            get { return _selectedAudioFiles.ToArray(); }
        }

        private GotLyricsMainForm _mainForm;
        /// <summary>
        /// Gets or sets the main form.
        /// </summary>
        /// <value>The main form.</value>
        internal GotLyricsMainForm MainForm
        {
            get { return _mainForm; }
            set { _mainForm = value; }
        }

        /// <summary>
        /// Gets the list view.
        /// </summary>
        /// <value>The list view.</value>
        public ListView ListView
        {
            get { return listView; }
        }
        
        #endregion

        #region Events

        private bool _doSelectionUpdate = true;

        /// <summary>
        /// Occurs when file selection has changed.
        /// </summary>
        public event EventHandler<AudioFileSelectionChangeEventArgs> SelectionChanged;

        #endregion

        public bool CanChangeFolder()
        {
            foreach (ListViewItem lvItem in listView.Items)
            {
                AudioFileContext audioFile = (AudioFileContext)lvItem.Tag;

                if (audioFile.IsModified)
                {
                    bool applyToAll = false;
                    DialogResult res = MessageBoxEx.Show(MainForm, 
                                                         "The file \"" + Path.GetFileName(audioFile.Filename) + "\" has been modified.\nDo you wish to save the changes?",
                                                         "Save changes?", "Apply to all items", ref applyToAll,
                                                         MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question);

                    switch (res)
                    {
                        case DialogResult.Yes:
                            if (applyToAll)
                                return SaveAllModifiedAudioFiles();

                            try
                            {
                                audioFile.Write();
                                audioFile.IsModified = false;
                            }
                            catch (Exception ex)
                            {
                                MainForm.Log.Write("Could not write to file \"" + audioFile.Filename + "\".", ex);
                                return false;
                            }

                            break;

                        case DialogResult.No:
                            if (applyToAll)
                                return true;
                            else
                                audioFile.IsModified = false;
                            break;

                        case DialogResult.Cancel:
                            return false;
                    }
                }
            }

            return true;
        }

        public bool SaveSelectedAudioFiles()
        {
            return Save(SelectedAudioFiles);
        }

        public bool SaveAllModifiedAudioFiles()
        {
            return Save(AudioFiles);
        }

        private bool Save(AudioFileContext[] audioFiles)
        {
            List<AudioFileContext> modifiedFiles = new List<AudioFileContext>();

            foreach (AudioFileContext audioFile in audioFiles)
            {
                if (audioFile.IsModified)
                    modifiedFiles.Add(audioFile);
            }

            ProgressDialog dlg = new ProgressDialog();

            dlg.Text = "Save";
            dlg.AutoClose = true;
            dlg.Argument = modifiedFiles;
            dlg.DoWork += new DoWorkEventHandler(SaveAllDialogProcess);

            DialogResult res = dlg.ShowDialog(MainForm);

            foreach (AudioFileContext audioFile in modifiedFiles)
                audioFile.ReflectListViewItem();

            if (res == DialogResult.OK)
                return true;

            if (dlg.Result.Exception != null)
            {
                MainForm.Log.Write(dlg.Result.Exception);
                return false;
            }

            return !dlg.Result.IsCancelled;
        }

        void SaveAllDialogProcess(object sender, DoWorkEventArgs e)
        {
            ProgressDialog dlg = (ProgressDialog)sender;

            List<AudioFileContext> audioFiles = (List<AudioFileContext>)e.Argument;

            double step = 100.0 / audioFiles.Count;

            for(int i = 0; i < audioFiles.Count; i++)
            {
                AudioFileContext audioFile = audioFiles[i];

                dlg.ReportProgress((int)((i + 1) * step + 0.5), "Saving " + Path.GetFileName(audioFile.Filename) + " ...");

                if (dlg.CancellationPending)
                {
                    e.Cancel = true;
                    break;
                }

                try
                {
                    audioFile.Write();
                }
                catch (Exception ex)
                {
                    throw (new Exception("Error occured while writing to the file \"" + audioFile.Filename + ".", ex));
                }

                audioFile.IsModified = false;
            }

            if (e.Cancel)
                dlg.ReportProgress(0, "Cancelled");
            else
                dlg.ReportProgress(100, "Done");
        }

        public void SetCurrentFolder(string folder)
        {
            try
            {
                MainForm.Log.Write("Switching folder.", folder);

                Cursor.Current = Cursors.WaitCursor;

                listView.Items.Clear();
                _audioFiles.Clear();
                _selectedAudioFiles.Clear();

                if (string.IsNullOrEmpty(folder) || !Directory.Exists(folder))
                    return;

                string[] files = Directory.GetFiles(folder, "*.mp3");

                foreach (string file in files)
                {
                    AudioFileContext audioFile = null;
                    ListViewItem lvItem = new ListViewItem();

                    try
                    {
                        MainForm.Log.Write("Adding file to list view.", file, LogLevel.Debug);

                        ShellPIDL pidl = new ShellPIDL(file);

                        lvItem.ImageIndex = pidl.IconIndex;
                        listView.Items.Add(lvItem);

                        audioFile = new AudioFileContext(lvItem, file);
                    }
                    catch (Exception ex)
                    {
                        listView.Items.Remove(lvItem);
                        MainForm.Log.Write("Failed processing the file \"" + file + "\".", ex);
                        continue;
                    }
                    
                    _audioFiles.Add(audioFile);
                }

                if (SelectionChanged != null)
                {
                    AudioFileSelectionChangeEventArgs e = new AudioFileSelectionChangeEventArgs(null);
                    SelectionChanged(this, e);
                }
            }
            finally
            {
                Cursor.Current = Cursors.Default;
            }
        }

        public void SetSelectionDirty()
        {
            foreach (AudioFileContext audioFile in _selectedAudioFiles)
            {
                audioFile.IsModified = true;
                audioFile.ReflectListViewItem();
            }
        }

        private void listView_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (!_doSelectionUpdate)
                return;

            // When multiple items are selected, the listview will fire a selection change event
            // for each one. By using a timer here we'll only update the selection for the last event.

            timerSelectionChanged.Start();
        }

        private void timerSelectionChanged_Tick(object sender, EventArgs e)
        {
            MainForm.Log.Write("Selected index changed.", LogLevel.Debug);

            timerSelectionChanged.Enabled = false;

            _selectedAudioFiles.Clear();

            foreach (ListViewItem item in listView.SelectedItems)
            {
                AudioFileContext audioFile = (AudioFileContext)item.Tag;
                _selectedAudioFiles.Add(audioFile);
            }

            if (SelectionChanged != null)
            {
                AudioFileSelectionChangeEventArgs args = new AudioFileSelectionChangeEventArgs(SelectedAudioFiles);
                SelectionChanged(this, args);
            }
        }

        private void listView_ColumnClick(object sender, ColumnClickEventArgs e)
        {
            //listView.ListViewItemSorter = new ListViewItemComparer(e.Column);
            listView.Sort();
        }

        internal void SelectAllItems()
        {
            try
            {
                _doSelectionUpdate = false;
                listView.SelectAllItems();
            }
            finally
            {
                _doSelectionUpdate = true;
            }

            listView_SelectedIndexChanged(this, null);
        }

        
    }
}
